from typing import Generator


class Context:


    def __init__(self, target, total, param_list, count_list) -> None:
        self.target = target
        self.total = total
        self.param_list = param_list
        self.count_list = count_list
        assert len(param_list) == len(count_list)
        self.v = target
        self.count_list_bak = count_list.copy()
        self.finish = False

    def count_list_sum(self, n) -> int:
        return sum(self.count_list[:n])

    def surplus(self, n) -> int:
        return self.total - self.count_list_sum(n)
    
    def last_count(self) -> int:
        n = len(self.count_list)
        self.count_list[n - 1] = self.surplus(n - 1)
        return self.count_list[n - 1]
    
    def resetZero(self, n):
        self.count_list[n:] = (len(self.count_list) - n) * [0]
    
    def calc(self) -> bool:
        v = abs(self.target - sum(self.arrayMultip(self.param_list, self.count_list)))

        if v <= self.v:
            
            self.v = v
            self.count_list_bak = self.count_list.copy()
            print(self.count_list_bak)
        return v == 0

    @staticmethod
    def arrayMultip(array1, array2):

        length = min(len(array1), len(array2)) 

        result = []
        for i in range(length):
            result.append(array1[i] * array2[i])

        return result

def loop(ctx:Context, curIndex) -> Generator:

    if curIndex == len(ctx.count_list) - 2:
        i = 0
        while ctx.count_list_sum(curIndex+1) <= ctx.total:
            ctx.count_list[curIndex] = i
            last = ctx.last_count()

            if last < 0:
                continue

            result = ctx.calc()

            if result:
                yield True
            i+=1
            
    else:
        i = 0
        while ctx.count_list_sum(curIndex+1) <= ctx.total:
            for result in loop(ctx, curIndex+1):
                if result:
                    yield True

            i += 1
            ctx.count_list[curIndex] = i
            ctx.resetZero(curIndex+1)
        
    return False

def exec(target: float, total: int, params) -> Generator:
    length = len(params)
    ctx = Context(target, total, params, [0] * length)

    if total < 0 or total == 0:
        ctx.finish = True
        yield ctx
        return

    
    if length == 0:
        ctx.finish = True
        yield ctx
        return
    
    if length == 1:
        ctx.finish = True

        if target / params[0] == total:
            yield Context(target, total, params, [total] + [0] * (length-1))
        else:
            
            yield ctx
        return
        
    
    ctx = Context(target, total, params, [0] * length)

    for result in loop(ctx, 0):
        if result:
            yield ctx


    ctx.count_list = ctx.count_list_bak
    ctx.finish = True

    yield ctx


    
if __name__ == "__main__":

    generator_ctx = exec(0.1894, 19, [0.0131, 0.0059])

    for ctx in generator_ctx:
        print('------------')
        print(ctx.v)
        print(ctx.count_list)
        print(ctx.count_list_bak)
        print('------------')
        

    